<template>
  <div class="menu-management ">
    <v-card exportparts="10" class="elevation-10 rounded-xl pa-2">
      <v-card-title class="d-flex align-center ">
        <span>菜单管理</span>
        <v-spacer></v-spacer>
        <v-btn v-if="$perms('system_menu_insert')" color="primary" @click="handleAdd">
          <v-icon start>mdi-plus</v-icon>
          新增菜单
        </v-btn>
      </v-card-title>

      <v-card-text>
        <!-- 树形列表头部 -->
        <v-row class="mb-2 font-weight-bold text-subtitle-2 bg-grey-lighten-4 pa-2 rounded">
          <v-col cols="2">名称</v-col>
          <v-col cols="1">类型</v-col>
          <v-col cols="1">排序</v-col>
          <v-col cols="1">隐藏</v-col>
          <v-col cols="1">总是显示</v-col>
          <v-col cols="2">路径</v-col>
          <v-col cols="2">组件路径</v-col>
          <v-col cols="1">标签</v-col>
          <v-col cols="1" class="text-end">操作</v-col>
        </v-row>

        <!-- 加载状态 -->
        <div v-if="loading" class="text-center py-8">
          <v-progress-circular indeterminate color="primary"></v-progress-circular>
          <div class="mt-2">正在加载...</div>
        </div>

        <!-- 树形列表 -->
        <div v-else-if="isShow">
          <menu-tree-node v-for="item in menuList" :key="item.id" :node="item" :level="0"
            :expanded-nodes="expandedNodes" :tmp-tree-data="tmpTreeData" @toggle-expand="toggleExpand"
            @load-children="loadChildren" @handle-add-child="handleAddChild" @handle-edit="handleEdit"
            @handle-delete="handleDelete" />
        </div>
      </v-card-text>
    </v-card>

    <!-- 编辑对话框 -->
    <MenuForm :visible="dialog" :title="formTitle" :form="editedItem" :parent-menu-name="parentMenuName"
      :form-status="formStatus" :eden-old-parent-id="edenOldParentId" :menu-type-options="menuTypeOptions"
      :no-yes-options="noYesOptions" :label-options="labelOptions" @update:visible="val => dialog = val"
      @update:form="val => editedItem = val" @save="save" @cancel="closeDialog" @showParentMenu="showParentMenu"
      @menuTypeChange="menuTypeChange" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, getCurrentInstance, computed } from 'vue';
import { getTreeLazy, doDelete } from '@/api/system/menu/menuManagement';
import { useMessage } from '@/composables/useMessage';
import MenuForm from './components/MenuForm.vue';
import MenuTreeNode from './components/MenuTreeNode.vue';
import { isNull } from '@/utils/validate';

const { proxy } = getCurrentInstance()!;
const { success: showSuccess, error: showError } = useMessage();

// 数据状态
const isShow = ref(true);
const loading = ref(true);
const menuList = ref<any[]>([]);
const expandedNodes = ref<Set<string>>(new Set());
const tmpTreeData = ref<Record<string, any>>({});

// 表单相关
const dialog = ref(false);
const formStatus = ref(true);
const edenOldParentId = ref('');
const parentMenuName = ref('');
const editedItem = ref<any>({});
const editedIndex = ref(-1);

// 组件引用
const menuForm = ref<{ showEdit: (row?: any) => void }>();

// 常量
const defaultNode = "0";

// 默认表单项
const defaultItem = {
  menuName: '',
  type: '1',
  permissions: '',
  sortNo: 1,
  hidden: '0',
  alwaysShow: '0',
  url: '',
  component: '',
  redirect: '',
  icon: '',
  label: []
};

// 计算属性
const formTitle = computed(() => (editedIndex.value === -1 ? '新增菜单' : '编辑菜单'));

// 字典选项
const menuTypeOptions = ref([
  { dictName: '菜单', dictValue: '1' },
  { dictName: '按钮', dictValue: '2' },
  { dictName: '外链', dictValue: '3' }
]);

const noYesOptions = ref([
  { dictName: '否', dictValue: '0' },
  { dictName: '是', dictValue: '1' }
]);

const labelOptions = ref([
  { dictName: '管理员', dictValue: '0' },
  { dictName: '普通用户', dictValue: '1' }
]);

onMounted(async () => {
  // 预加载字典数据
  await preloadDictionaries();
  // 获取菜单数据
  await fetchData();
});

/**
 * 预加载字典数据
 */
const preloadDictionaries = async () => {
  try {
    const dictTypes = ['menu_type', 'no_yes', 'menu_role_label'];
    const promises = dictTypes.map(typeCode => proxy?.$getDictListAsync(typeCode));
    await Promise.all(promises);
    console.log('菜单管理字典数据预加载完成');
  } catch (error) {
    console.error('菜单管理字典数据预加载失败:', error);
  }
};

/**
 * 获取菜单数据
 */
const fetchData = async () => {
  loading.value = true;
  try {
    const { data } = await getTreeLazy({ parentId: defaultNode });
    menuList.value = data || [];
  } catch (error) {
    console.error('获取菜单数据失败:', error);
    showError('获取菜单数据失败');
  } finally {
    setTimeout(() => {
      loading.value = false;
    }, 300);
  }
};

/**
 * 切换展开状态
 */
const toggleExpand = (nodeId: string) => {
  if (expandedNodes.value.has(nodeId)) {
    expandedNodes.value.delete(nodeId);
  } else {
    expandedNodes.value.add(nodeId);
  }
};

/**
 * 加载子节点
 */
const loadChildren = async (node: any): Promise<void> => {
  try {
    const { data } = await getTreeLazy({ parentId: node.id });
    const responseData = data || [];

    if (responseData && responseData.length > 0) {
      node.children = responseData;
      node.hasChildren = responseData.some((child: any) => child.hasChildren);
    } else {
      node.children = [];
      node.hasChildren = false;
    }
  } catch (error) {
    console.error('加载子节点失败:', error);
    showError('加载子节点失败');
    throw error; // 重新抛出错误以便子组件处理
  }
};

/**
 * 刷新节点
 */
const refreshNodeBy = (id?: any, isReLoad?: boolean) => {
  if (!isNull(isReLoad) && isReLoad === true) {
    isShow.value = false;
    menuList.value = [];
    tmpTreeData.value = {};
    setTimeout(() => {
      isShow.value = true;
      fetchData();
    }, 20);
    return;
  }

  const cache = tmpTreeData.value[id];
  if (isNull(cache)) {
    fetchData();
  } else {
    // 通过节点id找到对应树节点对象
    let tree = cache.tree;
    let treeNode = cache.treeNode;
    let resolve = cache.resolve;
    loadNode(tree, treeNode, resolve);
  }
};

/**
 * 懒加载节点
 */
const loadNode = async (tree: any, treeNode: any, resolve: any) => {
  try {
    const { data } = await getTreeLazy({ parentId: tree.id });
    const responseData = data || [];

    if (!responseData || responseData.length === 0) {
      console.log("需要重新加载路由视图");
      return;
    }

    tmpTreeData.value[tree.id] = { tree, treeNode, resolve };
    resolve(responseData);
  } catch (error) {
    console.error('懒加载节点失败:', error);
  }
};

/**
 * 添加菜单
 */
const handleAdd = () => {
  editedIndex.value = -1;
  editedItem.value = { ...defaultItem };
  dialog.value = true;
};

/**
 * 添加下级菜单
 */
const handleAddChild = (row: any) => {
  if (row.id) {
    editedIndex.value = -1;
    editedItem.value = {
      ...defaultItem,
      parentId: row.id,
      parentName: row.menuName
    };
    parentMenuName.value = row.menuName;
    dialog.value = true;
  }
};

/**
 * 编辑菜单
 */
const handleEdit = (row: any) => {
  if (row) {
    editedIndex.value = menuList.value.indexOf(row);
    editedItem.value = { ...row };

    // 处理标签字段 - 将逗号分隔的字符串转换为数组
    if (editedItem.value.label && typeof editedItem.value.label === 'string') {
      editedItem.value.label = editedItem.value.label.split(',').filter((l: string) => l.trim());
    }

    dialog.value = true;
  }
};

/**
 * 删除菜单
 */
const handleDelete = async (row: any) => {
  if (row.id) {
    const confirmed = confirm("你确定要删除当前项吗");
    if (confirmed) {
      try {
        const response = await doDelete({ id: row.id });
        showSuccess(response.data?.msg || "删除成功");
        await refreshNodeBy(row.parentId);
      } catch (error) {
        console.error('删除失败:', error);
        showError("删除失败");
      }
    }
  }
};

/**
 * 关闭对话框
 */
const closeDialog = () => {
  dialog.value = false;
  editedItem.value = { ...defaultItem };
  parentMenuName.value = '';
  editedIndex.value = -1;
};

/**
 * 保存菜单
 */
const save = async (savedData: any) => {
  try {
    console.log('菜单保存成功:', savedData);
    closeDialog();
    // 刷新菜单数据
    await fetchData();
  } catch (error) {
    console.error('保存后刷新失败:', error);
  }
};

/**
 * 显示父菜单选择
 */
const showParentMenu = () => {
  // TODO: 实现父菜单选择逻辑
  console.log('显示父菜单选择');
};

/**
 * 菜单类型变更
 */
const menuTypeChange = (val: string) => {
  // TODO: 实现类型变更逻辑
  console.log('菜单类型变更:', val);
};
</script>

<style scoped>
.menu-management {
  padding: 0;
}
</style>